package com.easyban.service.impl;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import com.easyban.Dto.FileInfoDto;
import com.easyban.Dto.SessionWebUserDto;
import com.easyban.Dto.UserSpaceDto;
import com.easyban.config.AppConfig;
import com.easyban.constants.Constants;
import com.easyban.entity.enums.*;
import com.easyban.entity.po.FileShare;
import com.easyban.entity.po.UserInfo;
import com.easyban.entity.query.FileShareQuery;
import com.easyban.entity.vo.UploadResultDto;
import com.easyban.exception.BusinessException;
import com.easyban.service.FileShareService;
import com.easyban.service.UserInfoService;
import com.easyban.utils.*;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.easyban.entity.query.FileInfoQuery;
import com.easyban.entity.po.FileInfo;
import com.easyban.entity.vo.PaginationResultVO;
import com.easyban.entity.query.SimplePage;
import com.easyban.mappers.FileInfoMapper;
import com.easyban.service.FileInfoService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;


/**
 * 文件信息 业务接口实现
 */
@Service("fileInfoService")
public class FileInfoServiceImpl implements FileInfoService {
	private final Logger logger= LoggerFactory.getLogger(FileInfoServiceImpl.class);

	@Resource
	private FileInfoMapper<FileInfo, FileInfoQuery> fileInfoMapper;
    @Resource
	private RedisUtils redisUtils;
	@Resource
	@Lazy
	private UserInfoService userInfoService;
	@Resource
	private AppConfig appConfig;
	@Resource
	@Lazy
	private FileInfoService fileInfoService;


	/**
	 * 根据条件查询列表
	 */
	@Override
	public List<FileInfo> findListByParam(FileInfoQuery param) {
		return this.fileInfoMapper.selectList(param);
	}

	/**
	 * 根据条件查询列表
	 */
	@Override
	public Integer findCountByParam(FileInfoQuery param) {
		return this.fileInfoMapper.selectCount(param);
	}

	/**
	 * 分页查询方法
	 */
	@Override
	public PaginationResultVO<FileInfo> findListByPage(FileInfoQuery param) {
		int count = this.findCountByParam(param);
		int pageSize = param.getPageSize() == null ? PageSize.SIZE15.getSize() : param.getPageSize();

		SimplePage page = new SimplePage(param.getPageNo(), count, pageSize);
		param.setSimplePage(page);
		List<FileInfo> list = this.findListByParam(param);
		PaginationResultVO<FileInfo> result = new PaginationResultVO(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);
		return result;
	}

	/**
	 * 新增
	 */
	@Override
	public Integer add(FileInfo bean) {
		return this.fileInfoMapper.insert(bean);
	}

	/**
	 * 批量新增
	 */
	@Override
	public Integer addBatch(List<FileInfo> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.fileInfoMapper.insertBatch(listBean);
	}

	/**
	 * 批量新增或者修改
	 */
	@Override
	public Integer addOrUpdateBatch(List<FileInfo> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.fileInfoMapper.insertOrUpdateBatch(listBean);
	}

	/**
	 * 多条件更新
	 */
	@Override
	public Integer updateByParam(FileInfo bean, FileInfoQuery param) {
		StringTools.checkParam(param);
		return this.fileInfoMapper.updateByParam(bean, param);
	}

	/**
	 * 多条件删除
	 */
	@Override
	public Integer deleteByParam(FileInfoQuery param) {
		StringTools.checkParam(param);
		return this.fileInfoMapper.deleteByParam(param);
	}

	/**
	 * 根据FileIdAndUserId获取对象
	 */
	@Override
	public FileInfo getFileInfoByFileIdAndUserId(String fileId, String userId) {
		return this.fileInfoMapper.selectByFileIdAndUserId(fileId, userId);
	}

	/**
	 * 根据FileIdAndUserId修改
	 */
	@Override
	public Integer updateFileInfoByFileIdAndUserId(FileInfo bean, String fileId, String userId) {
		return this.fileInfoMapper.updateByFileIdAndUserId(bean, fileId, userId);
	}

	/**
	 * 根据FileIdAndUserId删除
	 */
	@Override
	public Integer deleteFileInfoByFileIdAndUserId(String fileId, String userId) {
		return this.fileInfoMapper.deleteByFileIdAndUserId(fileId, userId);
	}

	@Override
	public Long fileSizeByuserId(String Userid) {
		return this.fileInfoMapper.selectUseSpace(Userid);
	}

	@Override
	public void transferFile(String fileId, SessionWebUserDto webUserDto) {
		Boolean transferSuccess = true;
		String targetFilePath = null;
		String cover = null;
		FileTypeEnums fileTypeEnum = null;
		FileInfo fileInfo = fileInfoMapper.selectByFileIdAndUserId(fileId, webUserDto.getUserId());
		try {
			if (fileInfo == null || !FileStatusEnums.TRANSFER.getStatus().equals(fileInfo.getStatus())) {
				return;
			}
			//临时目录
			String tempFolderName = appConfig.getProjectFolder() + Constants.FILE_FOLDER_TEMP;
			String currentUserFolderName = webUserDto.getUserId() + fileId;
			File fileFolder = new File(tempFolderName + currentUserFolderName);
			if (!fileFolder.exists()) {
				fileFolder.mkdirs();
			}
			//文件后缀
			String fileSuffix = StringTools.getFileSuffix(fileInfo.getFileName());
			String month = DateUtil.format(fileInfo.getCreateTime(), DateTimePatternEnum.YYYYMM.getPattern());
			//目标目录
			String targetFolderName = appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE;
			File targetFolder = new File(targetFolderName + "/" + month);
			if (!targetFolder.exists()) {
				targetFolder.mkdirs();
			}
			//真实文件名
			String realFileName = currentUserFolderName + fileSuffix;
			//真实文件路径
			targetFilePath = targetFolder.getPath() + "/" + realFileName;
			//合并文件
			union(fileFolder.getPath(), targetFilePath, fileInfo.getFileName(), true);
			//视频文件切割
			fileTypeEnum = FileTypeEnums.getFileTypeBySuffix(fileSuffix);
			if (FileTypeEnums.VIDEO == fileTypeEnum) {
				cutFile4Video(fileId, targetFilePath);
				//视频生成缩略图
				cover = month + "/" + currentUserFolderName + Constants.IMAGE_PNG_SUFFIX;
				String coverPath = targetFolderName + "/" + cover;
				ScaleFilter.createCover4Video(new File(targetFilePath), Constants.LENGTH_150, new File(coverPath));
			} else if (FileTypeEnums.IMAGE == fileTypeEnum) {
				//生成缩略图
				cover = month + "/" + realFileName.replace(".", "_.");
				String coverPath = targetFolderName + "/" + cover;
				Boolean created = ScaleFilter.createThumbnailWidthFFmpeg(new File(targetFilePath), Constants.LENGTH_150, new File(coverPath), false);
				if (!created) {
					FileUtils.copyFile(new File(targetFilePath), new File(coverPath));
				}
			}
		} catch (Exception e) {
			logger.error("文件转码失败，文件Id:{},userId:{}", fileId, webUserDto.getUserId(), e);
			transferSuccess = false;
		} finally {
			FileInfo updateInfo = new FileInfo();
			updateInfo.setFileSize(new File(targetFilePath).length());
			updateInfo.setFileCover(cover);
			updateInfo.setStatus(transferSuccess ? FileStatusEnums.USING.getStatus() : FileStatusEnums.TRANSFER_FAIL.getStatus());
			fileInfoMapper.updateFileStatusWithOldStatus(fileId, webUserDto.getUserId(), updateInfo, FileStatusEnums.TRANSFER.getStatus());
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void removeFile2RecycleBatch(String userId, String fileIds) {
		String[] split = fileIds.split(",");
		FileInfoQuery fileInfoQuery = new FileInfoQuery();
		fileInfoQuery.setFileIdArray(split);
		fileInfoQuery.setUserId(userId);
		fileInfoQuery.setDelFlag(FileDelFlagEnums.USING.getFlag());
		List<FileInfo> listByParam = fileInfoService.findListByParam(fileInfoQuery);
		if (listByParam.isEmpty()) {
			return;
		}
		List<String> delFilePidList = new ArrayList<>();
		for (FileInfo fileInfo : listByParam) {
			findAllSubFolderFileIdList(delFilePidList, userId, fileInfo.getFileId(), FileDelFlagEnums.USING.getFlag());
		}
		/*//将目录下的所有文件更新为已删除*/
		if (!delFilePidList.isEmpty()) {
			FileInfo updateInfo = new FileInfo();
			updateInfo.setDelFlag(FileDelFlagEnums.DEL.getFlag());
			this.fileInfoMapper.updateFileDelFlagBatch(updateInfo, userId, delFilePidList, null, FileDelFlagEnums.USING.getFlag());
		}

		/*将选中的文件更新为回收站*/

		List<String> delFileIdList = Arrays.asList(split);
		FileInfo fileInfo = new FileInfo();
		fileInfo.setRecoveryTime(new Date());
		fileInfo.setDelFlag(FileDelFlagEnums.RECYCLE.getFlag());
		this.fileInfoMapper.updateFileDelFlagBatch(fileInfo, userId, null, delFileIdList, FileDelFlagEnums.USING.getFlag());
	}
	private void findAllSubFolderFileIdList(List<String> fileIdList, String userId, String fileId, Integer delFlag) {
		/*回溯，查看目录下的子目录*/
		fileIdList.add(fileId);
		FileInfoQuery fileInfoQuery = new FileInfoQuery();
		fileInfoQuery.setUserId(userId);
		fileInfoQuery.setFilePid(fileId);
		fileInfoQuery.setDelFlag(delFlag);
		List<FileInfo> listByParam = fileInfoService.findListByParam(fileInfoQuery);
		for (FileInfo itm : listByParam) {
			findAllSubFolderFileIdList(fileIdList,userId,itm.getFileId(),delFlag);
		}
	}


	@Override
	@Transactional(rollbackFor = Exception.class)
	public void changeFileFolder(String fileIds, String filePid, String userId) {
		if (fileIds.equals(filePid)){
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		if (!Constants.ZERO_STR.equals(filePid)){
			FileInfo fileInfoByFileIdAndUserId = fileInfoService.getFileInfoByFileIdAndUserId(filePid, userId);
			if (fileInfoByFileIdAndUserId==null || !FileDelFlagEnums.USING.getFlag().equals(fileInfoByFileIdAndUserId.getDelFlag())){
				throw new BusinessException(ResponseCodeEnum.CODE_600);
			}
		}
		String[] split = fileIds.split(",");
		FileInfoQuery fileInfoQuery = new FileInfoQuery();
		fileInfoQuery.setFilePid(filePid);
		fileInfoQuery.setUserId(userId);
		/*
		* 要移到的那个目录的现有文件，用后面检测相同名字*/
		List<FileInfo> listByParam = fileInfoService.findListByParam(fileInfoQuery);
		Map<String, FileInfo> fileInfoMap = listByParam.stream().collect(Collectors.toMap(FileInfo::getFileName,
				Function.identity(), (file1, file2) -> file2));
		FileInfoQuery query = new FileInfoQuery();
		query.setUserId(userId);
		query.setFileIdArray(split);
		/*目前要移动的文件*/
		List<FileInfo> selectFileList = fileInfoService.findListByParam(query);
		/*检测那些文件是相同名字的，需要重命名*/
		for (FileInfo fileInfo : selectFileList) {
			FileInfo rootFileInfo = fileInfoMap.get(fileInfo.getFileName());
			//文件名已经存在，重命名被还原的文件名
			FileInfo updateInfo = new FileInfo();
			if (rootFileInfo != null) {
				String fileName = StringTools.rename(fileInfo.getFileName());
				updateInfo.setFileName(fileName);
			}
			updateInfo.setFilePid(filePid);
			this.fileInfoMapper.updateByFileIdAndUserId(updateInfo, fileInfo.getFileId(), userId);
		}
	}

	@Override
	public List<FileInfo> findListByParamAndExclude(String filePid, String currentFileIds) {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		HttpSession session = request.getSession();
		SessionWebUserDto sessionAttribute = (SessionWebUserDto) session.getAttribute(Constants.SESSION_KEY);
		FileInfoQuery query = new FileInfoQuery();
		query.setUserId(sessionAttribute.getUserId());
		query.setFilePid(filePid);
		query.setFolderType(FileFolderTypeEnums.FOLDER.getType());
		if (!StringTools.isEmpty(currentFileIds)) {
			query.setExcludeFileIdArray(currentFileIds.split(","));
		}
		query.setDelFlag(FileDelFlagEnums.USING.getFlag());
		query.setOrderBy("create_time desc");
		List<FileInfo> fileInfoList = fileInfoService.findListByParam(query);
		return fileInfoList;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public FileInfo rename(String fileId, String userId, String fileName) {
		//FileInfo fileInfo = new FileInfo();
		FileInfo fileInfo = this.fileInfoMapper.selectByFileIdAndUserId(fileId, userId);
		if (fileInfo==null){
			throw new BusinessException("文件不存在");
		}
		if (fileInfo.getFileName().equals(fileName)) {
			return fileInfo;
		}
		checkFolder(fileInfo.getFilePid(),userId,fileName,fileInfo.getFolderType());
		//获取后缀
		if (FileFolderTypeEnums.FILE.getType().equals(fileInfo.getFolderType())) {
			fileName = fileName + StringTools.getFileSuffix(fileInfo.getFileName());
		}
		Date curDate = new Date();
		FileInfo dbInfo = new FileInfo();
		dbInfo.setFileName(fileName);
		dbInfo.setLastUpdateTime(curDate);
		this.fileInfoMapper.updateByFileIdAndUserId(dbInfo, fileId, userId);
		FileInfoQuery fileInfoQuery = new FileInfoQuery();
		fileInfoQuery.setFileName(fileName);
		fileInfoQuery.setUserId(userId);
		fileInfoQuery.setFilePid(fileInfo.getFilePid());
		fileInfoQuery.setDelFlag(FileDelFlagEnums.USING.getFlag());
		Integer integer = this.fileInfoMapper.selectCount(fileInfoQuery);
		if (integer>1){
			throw new BusinessException("文件名" + fileName + "已经存在");
		}
		fileInfo.setFileName(fileName);
		fileInfo.setLastUpdateTime(curDate);
		return fileInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public FileInfo newFolder(String filePid, String userId, String fileName) {
		checkFolder(filePid,userId,fileName,FileFolderTypeEnums.FOLDER.getType());
		Date curDate = new Date();
		FileInfo fileInfo = new FileInfo();
		fileInfo.setFileId(StringTools.getRandomString(Constants.LENGTH_10));
		fileInfo.setUserId(userId);
		fileInfo.setFilePid(filePid);
		fileInfo.setFileName(fileName);
		fileInfo.setFolderType(FileFolderTypeEnums.FOLDER.getType());
		fileInfo.setCreateTime(curDate);
		fileInfo.setLastUpdateTime(curDate);
		fileInfo.setStatus(FileStatusEnums.USING.getStatus());
		fileInfo.setDelFlag(FileDelFlagEnums.USING.getFlag());
		this.fileInfoMapper.insert(fileInfo);

		return fileInfo;
	}
	private void checkFolder(String filePid, String userId, String fileName, Integer folderType){
		FileInfoQuery fileInfoQuery = new FileInfoQuery();
		fileInfoQuery.setFolderType(folderType);
		fileInfoQuery.setFilePid(filePid);
		fileInfoQuery.setUserId(userId);
		fileInfoQuery.setDelFlag(FileDelFlagEnums.USING.getFlag());
		fileInfoQuery.setFileName(fileName);
		Integer integer = this.fileInfoMapper.selectCount(fileInfoQuery);
		if (integer>0){
			throw new BusinessException("该目录已存在");
		}
		return;
	}


	private void cutFile4Video(String fileId, String videoFilePath) {
		//创建同名切片目录
		File tsFolder = new File(videoFilePath.substring(0, videoFilePath.lastIndexOf(".")));
		if (!tsFolder.exists()) {
			tsFolder.mkdirs();
		}
		//final String CMD_TRANSFER_2TS = "ffmpeg -y -i %s  -vcodec copy -acodec copy -vbsf h264_mp4toannexb %s";
		//final String CMD_CUT_TS = "ffmpeg -i %s -c copy -map 0 -f segment -segment_list %s -segment_time 30 %s/%s_%%4d.ts";
		final String CMD="ffmpeg -i %s -c:v h264 -flags +cgop -g 30 -hls_time 20 -hls_list_size 0 -hls_segment_filename %s_%%3d.ts %s";
		String tsPath = tsFolder + "/" + Constants.TS_NAME;
		//生成.ts
		//String cmd = String.format(CMD_TRANSFER_2TS, videoFilePath, tsPath);
		//ProcessUtils.executeCommand(cmd, false);
		//生成索引文件.m3u8 和切片.ts
		//cmd = String.format(CMD_CUT_TS, tsPath, tsFolder.getPath() + "/" + Constants.M3U8_NAME, tsFolder.getPath(), fileId);
		String cmd=String.format(CMD,videoFilePath,tsFolder.getPath()+"/"+fileId,tsFolder.getPath() + "/" + Constants.M3U8_NAME);
		System.out.println("指令"+cmd);
		ProcessUtils.executeCommand(cmd, false);
		//删除index.ts
		new File(tsPath).delete();
	}
	public static void union(String dirPath, String toFilePath, String fileName, boolean delSource) throws BusinessException {
		File dir = new File(dirPath);
		if (!dir.exists()) {
			throw new BusinessException("目录不存在");
		}
		File fileList[] = dir.listFiles();
		File targetFile = new File(toFilePath);
		RandomAccessFile writeFile = null;
		try {
			writeFile = new RandomAccessFile(targetFile, "rw");
			byte[] b = new byte[1024 * 10];
			for (int i = 0; i < fileList.length; i++) {
				int len = -1;
				//创建读块文件的对象
				File chunkFile = new File(dirPath + File.separator + i);
				RandomAccessFile readFile = null;
				try {
					readFile = new RandomAccessFile(chunkFile, "r");
					while ((len = readFile.read(b)) != -1) {
						writeFile.write(b, 0, len);
					}
				} catch (Exception e) {
					System.out.println(e.getMessage()+"合并失败");
					throw new BusinessException("合并文件失败");
				} finally {
					readFile.close();
				}
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
			throw new BusinessException("合并文件" + fileName + "出错了");
		} finally {
			try {
				if (null != writeFile) {
					writeFile.close();
				}
			} catch (IOException e) {
				System.out.println(e.getMessage());
			}
			if (delSource) {
				if (dir.exists()) {
					try {
						FileUtils.deleteDirectory(dir);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public UploadResultDto uploadFile(SessionWebUserDto sessionV, FileInfoDto fileInfoDto) {
		boolean uploadSuccess=true;
		File tempFileFolder = null;
		UploadResultDto uploadResultDto = new UploadResultDto();
		try {

		if (StringTools.isEmpty(fileInfoDto.getFileId())){
			fileInfoDto.setFileId(StringTools.getRandomString(Constants.LENGTH_10));
		}
		uploadResultDto.setFileId(fileInfoDto.getFileId());
		Date curDate = new Date();
		UserSpaceDto spaceDto = redisUtils.getFileSpace(sessionV.getUserId());
		if (fileInfoDto.getChunkIndex() == 0) {
			FileInfoQuery infoQuery = new FileInfoQuery();
			infoQuery.setFileMd5(fileInfoDto.getFileMd5());
			infoQuery.setSimplePage(new SimplePage(0, 1));
			infoQuery.setStatus(FileStatusEnums.USING.getStatus());
			List<FileInfo> dbFileList = this.fileInfoMapper.selectList(infoQuery);
			//秒传
			if (!dbFileList.isEmpty()) {
				FileInfo dbFile = dbFileList.get(0);
				//判断文件状态
				if (dbFile.getFileSize() + spaceDto.getUseSpace() > spaceDto.getTotalSpace()) {
					throw new BusinessException(ResponseCodeEnum.CODE_910);
				}
				dbFile.setFileId(fileInfoDto.getFileId());
				dbFile.setFilePid(fileInfoDto.getFilePid());
				dbFile.setUserId(sessionV.getUserId());
				dbFile.setFileMd5(null);
				dbFile.setCreateTime(curDate);
				dbFile.setLastUpdateTime(curDate);
				dbFile.setStatus(FileStatusEnums.USING.getStatus());
				dbFile.setDelFlag(FileDelFlagEnums.USING.getFlag());
				dbFile.setFileMd5(fileInfoDto.getFileMd5());
				fileInfoDto.setFileName(autoRename(fileInfoDto.getFilePid(), sessionV.getUserId(), fileInfoDto.getFileName()));
				dbFile.setFileName(fileInfoDto.getFileName());
				this.fileInfoMapper.insert(dbFile);
				uploadResultDto.setStatus(UploadStatusEnums.UPLOAD_SECONDS.getCode());
				//更新用户空间使用
				updateUserSpace(sessionV, dbFile.getFileSize());

				return uploadResultDto;
			}
		}
		//暂存在临时目录
		String tempFolderName = appConfig.getProjectFolder() + Constants.FILE_FOLDER_TEMP;
		String currentUserFolderName = sessionV.getUserId() + fileInfoDto.getFileId();
		logger.debug("目录+"+currentUserFolderName);
		//创建临时目录
		tempFileFolder = new File(tempFolderName + currentUserFolderName);
		if (!tempFileFolder.exists()) {
			tempFileFolder.mkdirs();
		}

		//判断磁盘空间
		Long currentTempSize = redisUtils.getFileTempSize(sessionV.getUserId(), fileInfoDto.getFileId());
		if (fileInfoDto.getFile().getSize() + currentTempSize + spaceDto.getUseSpace() > spaceDto.getTotalSpace()) {
			throw new BusinessException(ResponseCodeEnum.CODE_910);
		}

		File newFile = new File(tempFileFolder.getPath() + "/" + fileInfoDto.getChunkIndex());
		try {
			fileInfoDto.getFile().transferTo(newFile);
		} catch (IOException ex) {
			throw new RuntimeException(ex);
		}
		//保存临时大小
		redisUtils.saveFileTempSize(sessionV.getUserId(), fileInfoDto.getFileId(), fileInfoDto.getFile().getSize());
		//不是最后一个分片，直接返回
		if (fileInfoDto.getChunkIndex() < fileInfoDto.getChunks() - 1) {
			uploadResultDto.setStatus(UploadStatusEnums.UPLOADING.getCode());
			return uploadResultDto;
		}
		//最后一个分片上传完成，记录数据库，异步合并分片
		String month = DateUtil.format(curDate, DateTimePatternEnum.YYYYMM.getPattern());
		String fileSuffix = StringTools.getFileSuffix(fileInfoDto.getFileName());
		//真实文件名
		String realFileName = currentUserFolderName + fileSuffix;
		FileTypeEnums fileTypeEnum = FileTypeEnums.getFileTypeBySuffix(fileSuffix);
		//自动重命名
		//fileName = autoRename(fileInfoDto.getFilePid(), sessionV.getUserId(), fileInfoDto.getFileName());
		fileInfoDto.setFileName(autoRename(fileInfoDto.getFilePid(), sessionV.getUserId(), fileInfoDto.getFileName()));
		FileInfo fileInfo = new FileInfo();
		fileInfo.setFileId(fileInfoDto.getFileId());
		fileInfo.setUserId(sessionV.getUserId());
		fileInfo.setFileMd5(fileInfoDto.getFileMd5());
		fileInfo.setFileName(fileInfoDto.getFileName());
		fileInfo.setFilePath(month + "/" + realFileName);
		fileInfo.setFilePid(fileInfoDto.getFilePid());
		fileInfo.setCreateTime(curDate);
		fileInfo.setLastUpdateTime(curDate);
		fileInfo.setFileCategory(fileTypeEnum.getCategory().getCategory());
		fileInfo.setFileType(fileTypeEnum.getType());
		fileInfo.setStatus(FileStatusEnums.TRANSFER.getStatus());
		fileInfo.setFolderType(FileFolderTypeEnums.FILE.getType());
		fileInfo.setDelFlag(FileDelFlagEnums.USING.getFlag());
		this.fileInfoMapper.insert(fileInfo);

		Long totalSize = redisUtils.getFileTempSize(sessionV.getUserId(), fileInfoDto.getFileId());
		updateUserSpace(sessionV, totalSize);

		uploadResultDto.setStatus(UploadStatusEnums.UPLOAD_FINISH.getCode());
		//事务提交后调用异步方法
		TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
			@Override
			public void afterCommit() {
				fileInfoService.transferFile(fileInfo.getFileId(), sessionV);
			}
		});
		return uploadResultDto;
	} catch(BusinessException e) {
		uploadSuccess = false;
		logger.error("文件上传失败", e);
		throw e;
	} catch (Exception e) {
		uploadSuccess = false;
		logger.error("文件上传失败", e);
		throw new BusinessException("文件上传失败");
	} finally {
		//如果上传失败，清除临时目录
		if (tempFileFolder != null && !uploadSuccess) {
			try {
				FileUtils.deleteDirectory(tempFileFolder);
			} catch (IOException e) {
				logger.error("删除临时目录失败");
			}
		}
	}

	}
	private void updateUserSpace(SessionWebUserDto webUserDto, Long totalSize) {
		Integer count = userInfoService.updateUserSpace(webUserDto.getUserId(), totalSize, null);
		if (count == 0) {
			throw new BusinessException(ResponseCodeEnum.CODE_904);
		}
		UserSpaceDto spaceDto = redisUtils.getFileSpace(webUserDto.getUserId());
		spaceDto.setUseSpace(spaceDto.getUseSpace() + totalSize);
		redisUtils.saveUserSpaceUse(webUserDto.getUserId(), spaceDto);
	}
	private String autoRename(String filePid, String userId, String fileName) {
		FileInfoQuery fileInfoQuery = new FileInfoQuery();
		fileInfoQuery.setUserId(userId);
		fileInfoQuery.setFilePid(filePid);
		fileInfoQuery.setDelFlag(FileDelFlagEnums.USING.getFlag());
		fileInfoQuery.setFileName(fileName);
		Integer count = this.fileInfoMapper.selectCount(fileInfoQuery);
		if (count > 0) {
			return StringTools.rename(fileName);
		}

		return fileName;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void delFileBatch(String userId, String fileIds, boolean adminOp) {
		String[] fileIdArray = fileIds.split(",");

		FileInfoQuery query = new FileInfoQuery();
		query.setUserId(userId);
		query.setFileIdArray(fileIdArray);
		if(!adminOp){
			query.setDelFlag(FileDelFlagEnums.RECYCLE.getFlag());
		}
		List<FileInfo> fileInfoList = this.fileInfoMapper.selectList(query);
		List<String> delFileSubFolderFileIdList = new ArrayList<>();
		/*所选文件夹的中的子文件id*/
		for (FileInfo fileInfo : fileInfoList) {
			if (FileFolderTypeEnums.FOLDER.getType().equals(fileInfo.getFolderType())) {
				findAllSubFolderFileIdList(delFileSubFolderFileIdList, userId, fileInfo.getFileId(), FileDelFlagEnums.DEL.getFlag());
			}
			//fileShareService.findListByParam()
		}
		/*彻底删除，资源有限就不秒传了*/
		for (String itm : delFileSubFolderFileIdList) {
			FileInfo fileInfo = this.fileInfoMapper.selectByFileIdAndUserId(itm, userId);
			if (fileInfo.getFolderType()==0){
				/*文件本地也删除*/
				String path=appConfig.getProjectFolder()+Constants.FILE_FOLDER_FILE+fileInfo.getFilePath();
				File file = new File(path);
				file.delete();
			}
			/*数据库也删除*/
			FileInfoQuery fileInfoQuery = new FileInfoQuery();
			fileInfoQuery.setUserId(userId);
			fileInfoQuery.setFileId(itm);
			fileInfo.setDelFlag(FileDelFlagEnums.DEL.getFlag());
			fileInfoMapper.updateByParam(fileInfo,fileInfoQuery);
		}
		/**/
		List<String> list = Arrays.asList(fileIdArray);
		    for (String str : list) {
			FileInfo fileInfo = this.fileInfoMapper.selectByFileIdAndUserId(str, userId);
			if ( fileInfo != null && fileInfo.getFolderType()==0){
				/*文件本地也删除*/
				String path=appConfig.getProjectFolder()+Constants.FILE_FOLDER_FILE+fileInfo.getFilePath();
				File file = new File(path);
				file.delete();
			}
			/*数据库也删除*/
			FileInfoQuery fileInfoQuery = new FileInfoQuery();
			fileInfoQuery.setUserId(userId);
			fileInfoQuery.setFileId(str);
			fileInfo.setDelFlag(FileDelFlagEnums.DEL.getFlag());
			fileInfoMapper.updateByParam(fileInfo,fileInfoQuery);		}
		/*删除所选文件，子目录中的文件*//*
		if (!delFileSubFolderFileIdList.isEmpty()) {
			this.fileInfoMapper.delFileBatch(userId, delFileSubFolderFileIdList, null, adminOp ? null : FileDelFlagEnums.DEL.getFlag());
		}
		*//*删除所选文件*//*
		this.fileInfoMapper.delFileBatch(userId, null, Arrays.asList(fileIdArray), adminOp ? null : FileDelFlagEnums.RECYCLE.getFlag());*/

		/*更新一下用户缓存*/
		Long useSpace = this.fileInfoMapper.selectUseSpace(userId);
		UserInfo userInfo = new UserInfo();
		userInfo.setUseSpace(useSpace);
		userInfoService.updateByUserId(userInfo, userId);

		/*更新redis中的缓存*/
		UserSpaceDto userSpaceDto = redisUtils.getFileSpace(userId);
		userSpaceDto.setUseSpace(useSpace);
		redisUtils.saveUserSpaceUse(userId, userSpaceDto);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void recoverFileBatch(String userId, String fileIds) {
		String[] split = fileIds.split(",");
		FileInfoQuery infoQuery = new FileInfoQuery();
		infoQuery.setFileIdArray(split);
		infoQuery.setDelFlag(FileDelFlagEnums.RECYCLE.getFlag());
		infoQuery.setUserId(userId);
		/*回收站中的文件*/
		List<FileInfo> fileInfoList = this.fileInfoMapper.selectList(infoQuery);
		/*查找目录中的文件或者子目录的中的文件id*/
		ArrayList<String> delFileSubFolderFileIdList = new ArrayList<>();
		for (FileInfo fileInfo : fileInfoList) {
			if (FileFolderTypeEnums.FOLDER.getType().equals(fileInfo.getFolderType())){
				findAllSubFolderFileIdList(delFileSubFolderFileIdList, userId, fileInfo.getFileId(), FileDelFlagEnums.DEL.getFlag());
			}
		}
		/*查找根目录，下面还要查看重复名字呢*/
		infoQuery=new FileInfoQuery();
		infoQuery.setUserId(userId);
		infoQuery.setUserId(userId);
		infoQuery.setDelFlag(FileDelFlagEnums.USING.getFlag());
		infoQuery.setFilePid(Constants.ZERO_STR);
		List<FileInfo> rootfileInfoList = this.fileInfoMapper.selectList(infoQuery);
		Map<String, FileInfo> fileInfoMap = rootfileInfoList.stream().collect(Collectors.toMap(FileInfo::getFileName, Function.identity()
				, (file1, file2) -> file2));
		/*先把文件（不是目录）改正常*/
		if (!delFileSubFolderFileIdList.isEmpty()){
			FileInfo fileInfo = new FileInfo();
			fileInfo.setDelFlag(FileDelFlagEnums.USING.getFlag());
			this.fileInfoMapper.updateFileDelFlagBatch(fileInfo, userId, delFileSubFolderFileIdList, null, FileDelFlagEnums.DEL.getFlag());
		}
		/*将选中的文件更新为正常,且父级目录更到目录，就是还原后直接跑根目录了*/
		List<String> splitList = Arrays.asList(split);
		FileInfo fileInfo = new FileInfo();
		fileInfo.setDelFlag(FileDelFlagEnums.USING.getFlag());
		fileInfo.setFilePid(Constants.ZERO_STR);
		fileInfo.setLastUpdateTime(new Date());
		this.fileInfoMapper.updateFileDelFlagBatch(fileInfo, userId, null, splitList, FileDelFlagEnums.RECYCLE.getFlag());
		/*如果名字已存在就改一下*/
		for (FileInfo info : fileInfoList) {
			FileInfo fileInfo1 = fileInfoMap.get(info.getFileName());
			if (fileInfo1!=null){
				String rename = StringTools.rename(info.getFileName());
				FileInfo updateinfo = new FileInfo();
				updateinfo.setFileName(rename);
				this.fileInfoMapper.updateByFileIdAndUserId(updateinfo, info.getFileId(), userId);
			}
		}
	}

	@Override
	public void checkRootFilePid(String rootFilePid, String userId, String fileId) {
		if (StringTools.isEmpty(fileId)) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		if (rootFilePid.equals(fileId)) {
			return;
		}
		checkFilePid(rootFilePid, fileId, userId);
	}

	private void checkFilePid(String rootFilePid, String fileId, String userId) {
		FileInfo fileInfo = this.fileInfoMapper.selectByFileIdAndUserId(fileId, userId);
		if (fileInfo == null) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		if (Constants.ZERO_STR.equals(fileInfo.getFilePid())) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		if (fileInfo.getFilePid().equals(rootFilePid)) {
			return;
		}
		checkFilePid(rootFilePid, fileInfo.getFilePid(), userId);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveShare(String shareRootFilePid, String shareFileIds, String myFolderId, String shareUserId, String cureentUserId) {
		String[] shareFileIdArray = shareFileIds.split(",");
		/*所选中的目录中的文件和子目录，保存文件得指定目录保存*/
		FileInfoQuery fileInfoQuery = new FileInfoQuery();
		fileInfoQuery.setUserId(cureentUserId);
		fileInfoQuery.setFilePid(myFolderId);
		List<FileInfo> currentFileList = this.fileInfoMapper.selectList(fileInfoQuery);
		Map<String, FileInfo> currentFileMap = currentFileList.stream().
				collect(Collectors.toMap(FileInfo::getFileName, Function.identity(), (file1, file2) -> file2));
		/*选择的文件*/
		fileInfoQuery = new FileInfoQuery();
		fileInfoQuery.setUserId(shareUserId);
		fileInfoQuery.setFileIdArray(shareFileIdArray);
		List<FileInfo> shareFileList = this.fileInfoMapper.selectList(fileInfoQuery);
		//重命名选择的文件
		List<FileInfo> copyFileList = new ArrayList<>();
		Date curDate = new Date();
		for (FileInfo item : shareFileList) {
			FileInfo haveFile = currentFileMap.get(item.getFileName());
			if (haveFile != null) {
				item.setFileName(StringTools.rename(item.getFileName()));
			}
			findAllSubFile(copyFileList, item, shareUserId, cureentUserId, curDate, myFolderId);
		}
		System.out.println(copyFileList.size());
		this.fileInfoMapper.insertBatch(copyFileList);

		/*更新用户空间*/
		long paceSize=0;
		for (FileInfo fileInfo : copyFileList) {
			if (fileInfo.getFileSize()!=null){
				paceSize+=fileInfo.getFileSize();
			}
		}
		UserInfo userId = userInfoService.getUserInfoByUserId(cureentUserId);
		if (userId==null || userId.getStatus().equals(UserStatusEnum.DISABLE.getStatus())){
			throw new BusinessException("用户不存在或者被禁用");
		}
		if (userId.getTotalSpace()-userId.getUseSpace()<=paceSize){
			throw new BusinessException("文件太大了，无法保存,充个个会员吧~");
		}
		UserInfo userInfo = new UserInfo();
		userInfo.setUseSpace(userId.getUseSpace()+paceSize);
		userInfoService.updateByUserId(userInfo,cureentUserId);
		/*更新用户缓存空间*/
		UserSpaceDto value = (UserSpaceDto)redisUtils.getValue(Constants.READIS_SPACE+cureentUserId);
		value.setUseSpace(userId.getUseSpace()+paceSize);
		redisUtils.cacheValue(Constants.READIS_SPACE+cureentUserId,value);
	}
	/*查目录下的目录*/
	private void findAllSubFile(List<FileInfo> copyFileList, FileInfo fileInfo, String sourceUserId, String currentUserId, Date curDate, String newFilePid) {
		String sourceFileId = fileInfo.getFileId();
		fileInfo.setCreateTime(curDate);
		fileInfo.setLastUpdateTime(curDate);
		fileInfo.setFilePid(newFilePid);
		fileInfo.setUserId(currentUserId);
		String newFileId = StringTools.getRandomString(Constants.LENGTH_10);
		fileInfo.setFileId(newFileId);
		copyFileList.add(fileInfo);
		if (FileFolderTypeEnums.FOLDER.getType().equals(fileInfo.getFolderType())) {
			FileInfoQuery query = new FileInfoQuery();
			query.setFilePid(sourceFileId);
			query.setUserId(sourceUserId);
			List<FileInfo> sourceFileList = this.fileInfoMapper.selectList(query);
			for (FileInfo item : sourceFileList) {
				findAllSubFile(copyFileList, item, sourceUserId, currentUserId, curDate, newFileId);
			}
		}
	}
}